package cn.t.facade.device;


import cn.t.constants.CommonConstants;
import cn.t.constants.ResponseError;
import cn.t.converter.device.CargowayDTOConverter;
import cn.t.converter.device.DeviceDTOConverter;
import cn.t.converter.order.ReplenishmentRecordDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.PageInfoDTO;
import cn.t.core.mode.PageQueryDTO;
import cn.t.dto.device.DeviceDTO;
import cn.t.dto.device.DeviceVersionDTO;
import cn.t.enums.device.DeviceTypeEnum;
import cn.t.enums.order.ErrorEnum;
import cn.t.facade.user.UserInfoFacade;
import cn.t.model.device.AngleDO;
import cn.t.model.device.CargowayDO;
import cn.t.model.device.CargowaySkuDO;
import cn.t.model.device.DeviceDO;
import cn.t.model.order.ReplenishmentRecordDO;
import cn.t.model.sku.SkuDO;
import cn.t.request.CreateDeviceReq;
import cn.t.request.DeviceConfigReq;
import cn.t.request.InventoryReq;
import cn.t.request.OnOffShelfReq;
import cn.t.request.QueryDeviceReq;
import cn.t.service.device.AngleService;
import cn.t.service.device.ApkService;
import cn.t.service.device.CargowayService;
import cn.t.service.device.CargowaySkuService;
import cn.t.service.device.DeviceAndroidConfigService;
import cn.t.service.device.DeviceService;
import cn.t.service.order.ReplenishmentRecordService;
import cn.t.service.sku.SkuService;
import cn.t.service.user.CustomerFirmService;
import cn.t.utils.BusinessUtil;
import cn.t.utils.DateUtil;
import cn.t.utils.RandomUtil;
import cn.t.vo.HardwareConfigDetailVO;
import cn.t.vo.HardwareConfigVO;
import cn.t.vo.andriod.AndroidDeviceAngleVO;
import cn.t.vo.andriod.AndroidDeviceVO;
import cn.t.vo.device.DeviceBaseInfoVO;
import cn.t.vo.device.DeviceConfigVO;
import cn.t.vo.device.DeviceDetailVO;
import cn.t.vo.device.DeviceOverviewVO;
import cn.t.vo.device.DeviceVO;
import cn.t.vo.device.InventoryCargowayExcelVO;
import cn.t.vo.device.InventoryCargowayVO;
import cn.t.vo.device.InventoryDeviceExcelVO;
import cn.t.vo.device.InventoryDeviceVO;
import cn.t.vo.device.InventorySkuExcelVO;
import cn.t.vo.device.InventorySkuVO;
import cn.t.vo.ent.EntDeviceDetailVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 设备表(Device)服务编排
 *
 * @author t
 * @since 2024-05-24 10:19:33
 */
@Slf4j
@Service
@AllArgsConstructor
public class DeviceFacade extends FacadeImpl<DeviceDTO, DeviceDO, DeviceDTOConverter, DeviceService> {

    private final CargowayService cargowayService;
    private final CargowaySkuService cargowaySkuService;
    private final CustomerFirmService customerFirmService;
    private final SkuService skuService;
    private final CargowayDTOConverter cargowayDTOConverter;
    private final UserInfoFacade userInfoFacade;
    private final ReplenishmentRecordService replenishmentRecordService;
    private final ApkService apkService;
    private final ReplenishmentRecordDTOConverter replenishmentRecordDTOConverter;
    private final DeviceAndroidConfigService deviceAndroidConfigService;
    private final AngleService angleService;

    public DeviceOverviewVO overview(Long firmId) {

        Map<String, Long> overviewMap = service.overview(firmId);
        return new DeviceOverviewVO(overviewMap.getOrDefault("deviceNum", 0L),
                overviewMap.getOrDefault("onlineDeviceNum", 0L),
                overviewMap.getOrDefault("offlineDeviceNum", 0L), overviewMap.getOrDefault("banDeviceNum", 0L));
    }

    public List<DeviceDTO> queryById(Collection<Long> deviceIdSet) {
        List<DeviceDO> deviceList = service.queryById(deviceIdSet);
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        return deviceList.stream().map(converter::model2Dto).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean add(CreateDeviceReq request) {
        String imei = UUID.randomUUID().toString();
        // 生成 pin
        String pin = RandomUtil.generateCode(CommonConstants.SIXTEEN, true);
        List<DeviceDO> deviceDOS = request.getDevices().stream().map(f -> this.converter.createParam2do(request, f, imei, pin)).collect(Collectors.toList());


        Integer incrementNum = 1;
        boolean isFirst = true;
        for (DeviceDO deviceDO:deviceDOS) {

            if (isFirst) {
                deviceDO.setIsMaster(CommonConstants.ONE);
                isFirst = false;
            } else {
                deviceDO.setIsMaster(CommonConstants.ZERO);
            }
            // 添加设备
            long deviceId = this.service.addAndReturnId(deviceDO);

            // 主设备添加成功自动绑定全量发布的配置
            if (CommonConstants.ONE.equals(deviceDO.getIsMaster())) {
                this.deviceAndroidConfigService.bindFullPublishConfigs(deviceId);
            }

            // 添加货道
            List<CargowayDO> cargowayDOS = new ArrayList<>();
            if (Objects.equals(DeviceTypeEnum.ROTATING_CABINET.getCode(), deviceDO.getDeviceType())) {
                // 旋转柜
                if (!CollectionUtils.isEmpty(deviceDO.getRotatingCabinets())) {
                    // 获取旋转柜角度
                    List<AngleDO> angleDOs = angleService.getAll();
                    Map<Integer, List<AngleDO>> angleMap = angleDOs.stream().collect(Collectors.groupingBy(AngleDO::getLayerCargowayNum));
                    for (DeviceDO.RotatingCabinetInfo entity : deviceDO.getRotatingCabinets()) {
                        incrementNum = this.cargowayService.buildRotatingCabinetsCargowayDO(deviceId, incrementNum,
                                entity.getStoreyNum(), entity.getCargowayNum(), cargowayDOS, angleMap);
                    }
                }
            } else {
                for (int line = 0; line < deviceDO.getLineNum(); line++) {
                    for (int column = 0; column < deviceDO.getColumnNum(); column++) {
                        CargowayDO cargowayDO = this.cargowayService.buildCargowayDO(deviceId, incrementNum, line, column);
                        cargowayDOS.add(cargowayDO);
                        incrementNum++;
                    }
                }
            }

            cargowayService.batchSave(cargowayDOS);

            // 开放式货架自动创建领料员
            if (CommonConstants.FOUR.equals(deviceDO.getDeviceType())) {
                userInfoFacade.createByFirmDevice(request.getFirmId(), deviceId);
            }
        }
        return true;
    }

    public PageInfoDTO<DeviceVO> page(PageQueryDTO<QueryDeviceReq> request) {
        // 查询所有设备
        List<DeviceDO> allDevices = this.service.findByModel(new DeviceDO(), CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
        // 根据imei分组
        Map<String, List<DeviceDO>> allDeviceMap = allDevices.stream().collect(Collectors.groupingBy(DeviceDO::getImei));
        // 主设备
        List<DeviceDO> mainDevices = allDevices.stream().filter(f -> CommonConstants.ONE.equals(f.getIsMaster())).collect(Collectors.toList());
        // 主设备填充页面显示数据（因为要根据缺货率排序分页，只能提前填充）
        this.fillExtraData(mainDevices, allDeviceMap);
        // 内存分页数据集(只针对主设备)
        List<DeviceDO> divideDevices = this.service.getRecords(mainDevices, request.getParam(), request.getPageNo(), request.getPageSize());

        List<DeviceVO> records = this.converter.do2Vo(divideDevices);
        // 数量
        long total = this.service.getTotal(mainDevices, request.getParam());

        return new PageInfoDTO<>(request.getPageNo(), request.getPageSize(), total, records);
    }

    public PageInfoDTO<DeviceConfigVO> configPage(PageQueryDTO<DeviceConfigReq> request) {
        DeviceDO queryParams = this.converter.configReq2Do(request.getParam());
        queryParams.setIsMaster(CommonConstants.ONE);
        List<DeviceDO> deviceDOS = this.service.findByModel(queryParams, request.getStart(), request.getPageSize(), " gmt_created", " desc");
        long total = this.service.count(queryParams);

        List<Long> firmIds = deviceDOS.stream().map(DeviceDO::getFirmId).collect(Collectors.toList());
        Map<Long, String> firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);
        List<DeviceConfigVO> records = deviceDOS.stream().map(f -> converter.do2ConfigVo(f, firmIdNameMap.get(f.getFirmId()))).collect(Collectors.toList()) ;

        return new PageInfoDTO<>(request.getPageNo(), request.getPageSize(), total, records);
    }

    public PageInfoDTO<HardwareConfigVO> hardwarePage(PageQueryDTO<DeviceConfigReq> request) {
        DeviceDO queryParams = this.converter.configReq2Do(request.getParam());
        queryParams.setIsMaster(CommonConstants.ONE);
        queryParams.setStatus(CommonConstants.ONE);
        List<DeviceDO> deviceDOS = this.service.findByModel(queryParams, request.getStart(), request.getPageSize(), " gmt_created", " desc");

        // 填充统计数据
        long total = this.service.count(queryParams);
        List<HardwareConfigVO> records = this.converter.do2HardwareConfigVo(deviceDOS);
        this.fillHardwarePageData(records);
        return new PageInfoDTO<>(request.getPageNo(), request.getPageSize(), total, records);
    }

    private void fillHardwarePageData(List<HardwareConfigVO> records) {
        // 查出当前页相关的所有设备
        if (CollectionUtils.isEmpty(records)) {
            return;
        }
        List<String> imeiList = records.stream().map(HardwareConfigVO::getImei).collect(Collectors.toList());
        DeviceDO queryParams = new DeviceDO();
        queryParams.setImeiList(imeiList);
        List<DeviceDO> deviceDOS = this.service.findByModel(queryParams, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
        Map<String, List<DeviceDO>> deviceMap = deviceDOS.stream().collect(Collectors.groupingBy(DeviceDO::getImei));

        // 查询所有相关货道
        List<Long> deviceIds = deviceDOS.stream().map(DeviceDO::getId).collect(Collectors.toList());
        List<Long> firmIds = deviceDOS.stream().map(DeviceDO::getFirmId).collect(Collectors.toList());
        CargowayDO cargowayQueryParams = new CargowayDO();
        cargowayQueryParams.setDeviceIds(deviceIds);
        List<CargowayDO> cargowayDOS = this.cargowayService.findByModel(cargowayQueryParams, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);

        Map<Long, String> firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);

        records.forEach(r -> {
            List<DeviceDO> currentDevices = deviceMap.get(r.getImei());
            List<Long> currentDeviceIds = currentDevices.stream().map(DeviceDO::getId).collect(Collectors.toList());
            List<CargowayDO> currentCargowayList = cargowayDOS.stream().filter(c -> currentDeviceIds.contains(c.getDeviceId())).collect(Collectors.toList());

            long gravityScaleNum = currentCargowayList.stream().map(CargowayDO::getGravityScaleNo).filter(Objects::nonNull).distinct().count();
            long doorLockNum = currentCargowayList.stream().map(CargowayDO::getDoorLockNo).filter(Objects::nonNull).distinct().count();
            long ledNum = currentCargowayList.stream().map(CargowayDO::getLedNo).filter(Objects::nonNull).distinct().count();
            long motorNum = currentCargowayList.stream().map(CargowayDO::getMotorNo).filter(Objects::nonNull).distinct().count();

            r.setCargowayNum(currentCargowayList.size()).setGravityScaleNum(gravityScaleNum).setDoorLockNum(doorLockNum)
                    .setLedNum(ledNum).setMotorNum(motorNum).setFirmName(firmIdNameMap.get(r.getFirmId()));
        });
    }

    private void fillExtraData(List<DeviceDO> mainDevices, Map<String, List<DeviceDO>> allDeviceMap) {

        List<Long> firmIds = mainDevices.stream().map(DeviceDO::getFirmId).collect(Collectors.toList());
        Map<Long, String> firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);

        mainDevices.forEach(f -> {
            // 获取所有主副设备id
            List<Long> deviceIds = allDeviceMap.get(f.getImei()).stream().map(DeviceDO::getId).collect(Collectors.toList());
            // 所有设备货道
            List<CargowayDO> cargowayDOS = this.cargowayService.getCargowayList(deviceIds);
            // 所有设备商品
            CargowaySkuDO skuQueryParams = new CargowaySkuDO();
            skuQueryParams.setDeviceIds(deviceIds);
            List<CargowaySkuDO> cargowaySkuDOS = this.cargowaySkuService.findByModel(skuQueryParams, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
            // 只计算有商品的货道总容量
            Set<Long> cargowayIds = cargowayDOS.stream().map(CargowayDO::getId).collect(Collectors.toSet());
            // 设备货道总容量
            int totalCargowayVol = cargowayDOS.stream().filter(c -> cargowayIds.contains(c.getId())).mapToInt(CargowayDO::getCargowayVol).sum();
            // 设备商品系统库存总和
            int totalSkuInventory = cargowaySkuDOS.stream().mapToInt(CargowaySkuDO::getInventory).sum();
            // 填充缺货率
            f.setStockRate((new BigDecimal(100).subtract(BusinessUtil.getStockRate(totalSkuInventory, totalCargowayVol))) + "%" );
            // 填充货道数量
            f.setCargowayQty(cargowayDOS.size());
            // 填充主副柜类型
            List<Integer> deviceTypes = allDeviceMap.get(f.getImei()).stream().map(DeviceDO::getDeviceType).collect(Collectors.toList());
            f.setDeviceTypeName(DeviceTypeEnum.combineName(deviceTypes, CommonConstants.SLASH));
            // 填充公司名称
            f.setFirmName(firmIdNameMap.get(f.getFirmId()));
            // 填充在线/离线状态
            int onlineStatus = f.getGmtConnect() == null || DateUtil.diffTime(f.getGmtConnect(), new Date(), TimeUnit.MINUTES) > CommonConstants.FIFTEEN ? CommonConstants.ZERO : CommonConstants.ONE;
            f.setOnlineStatus(onlineStatus);
        });
    }

    public DeviceDetailVO detail(Long deviceId) {
        // 查询设备信息
        DeviceDO currentDevice = this.service.findById(deviceId);
        // 查询所有主副柜信息
        DeviceDO deviceQueryParam = new DeviceDO();
        deviceQueryParam.setImei(currentDevice.getImei());
        List<DeviceDO> devices = this.service.findByModel(deviceQueryParam, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);

        List<Long> deviceIds = devices.stream().map(DeviceDO::getId).collect(Collectors.toList());
        // 根据设备对货道分组
        Map<Long, List<CargowayDO>> cargowayMap = this.cargowayService.getCargowayMap(devices);

        // 所有设备商品
        CargowaySkuDO cargowaySkuQueryParams = new CargowaySkuDO();
        cargowaySkuQueryParams.setDeviceIds(deviceIds);
        List<CargowaySkuDO> cargowaySkuDOS = this.cargowaySkuService.findByModel(cargowaySkuQueryParams, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
        // 根据设备对商品分组
        Map<Long, List<CargowaySkuDO>> cargowaySkuMap = cargowaySkuDOS.stream().collect(Collectors.groupingBy(CargowaySkuDO::getDeviceId));

        List<DeviceDetailVO.CabinetInfo> cabinets = new ArrayList<>();
        devices.stream().sorted(Comparator.comparing(DeviceDO::getIsMaster).reversed()).forEach(device -> {
            DeviceDetailVO.CabinetInfo cabinet = new DeviceDetailVO.CabinetInfo();
            this.fillCabinetData(device, cabinet, cargowayMap, cargowaySkuMap);
            cabinets.add(cabinet);
        });

        return new DeviceDetailVO(currentDevice.getDeviceName(), cabinets);
    }

    private void fillCabinetData(DeviceDO device, DeviceDetailVO.CabinetInfo cabinetInfo, Map<Long, List<CargowayDO>> cargowayMap, Map<Long, List<CargowaySkuDO>> cargowaySkuMap) {
        if (CollectionUtils.isEmpty(cargowayMap)) {
            throw new BizException(ErrorEnum.ABNORMAL_DATA, String.format(ErrorEnum.ABNORMAL_DATA.getMessage(), ",设备id:" + device.getId()));
        }
        List<CargowayDO> cargowayDOS = cargowayMap.get(device.getId());

        List<CargowaySkuDO> cargowaySkuDOS = cargowaySkuMap.get(device.getId());
        Map<Long, CargowaySkuDO> csMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(cargowaySkuDOS)) {
            cargowaySkuDOS.forEach(f -> csMap.put(f.getCargowayId(), f));
        }

        // 货道容量
        int cargowayVol = cargowayDOS.stream().mapToInt(CargowayDO::getCargowayVol).sum();
        // 库存总量
        int skuInventory = CollectionUtils.isEmpty(cargowaySkuDOS) ? 0 : cargowaySkuDOS.stream().mapToInt(CargowaySkuDO::getInventory).sum();

        cabinetInfo.setDeviceId(device.getId());
        cabinetInfo.setDeviceType(device.getDeviceType());
        cabinetInfo.setDeviceTypeName(DeviceTypeEnum.getName(device.getDeviceType()));
        cabinetInfo.setCargowayNum(cargowayDOS.size());
        cabinetInfo.setCargowayVol((cargowayVol));
        cabinetInfo.setSkuNum(CollectionUtils.isEmpty(cargowaySkuDOS) ? 0 : cargowaySkuDOS.size());
        cabinetInfo.setInventoryQty(skuInventory);
        cabinetInfo.setStockRate((new BigDecimal(100).subtract(BusinessUtil.getStockRate(skuInventory, cargowayVol))) + "%");

        List<DeviceDetailVO.CargowayDetail> cargowayDetails = new ArrayList<>();

        cargowayDOS.forEach(cargoway -> {

            CargowaySkuDO cargowaySku = csMap.get(cargoway.getId());
            cargowayDetails.add(this.cargowayDTOConverter.data2CargowayDetailVo(cargoway, cargowaySku));
        });
        cabinetInfo.setCargowayDetails(cargowayDetails);
    }

    public Boolean onOffShelf(OnOffShelfReq request) {
        // 查询商品信息
        SkuDO sku = this.skuService.findById(request.getSkuId());

        if (ObjectUtils.isEmpty(sku)) {
            throw new BizException(ResponseError.SKU_NOT_EXIST, String.format(ResponseError.SKU_NOT_EXIST.getName(), request.getSkuId()));
        }

        // 计算货道商品总重量
        CargowaySkuDO cargowaySku = this.converter.req2CargowaySku(sku, request);
        if (CommonConstants.ONE.equals(request.getOprType())) {
            // 查看是否有上架商品
            CargowaySkuDO skuQueryParams = new CargowaySkuDO();
            skuQueryParams.setCargowayId(request.getCargowayId());
            List<CargowaySkuDO> cargowaySkuDOS = this.cargowaySkuService.findByModel(skuQueryParams, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);

            if (!CollectionUtils.isEmpty(cargowaySkuDOS)) {
                throw new BizException(ErrorEnum.DATA_ALREADY_EXISTS, String.format(ErrorEnum.DATA_ALREADY_EXISTS.getMessage(), "上架商品"));
            }
            cargowaySku.setWeight(new BigDecimal("0.00"));

            // 货道商品关系表数据
            this.cargowaySkuService.add(cargowaySku);
            // 更新货道表冗余信息
            this.cargowayService.updateCargoway(request.getCargowayId(), request.getCargowayVol());
        } else if (CommonConstants.TWO.equals(request.getOprType())) {
            // 删除货道商品关系表数据
            this.cargowaySkuService.removeById(request.getCargowaySkuId());
            // 更新货道表冗余信息
            this.cargowayService.updateCargoway(request.getCargowayId(), CommonConstants.ONE);
        } else if (CommonConstants.THREE.equals(request.getOprType())) {
            // 货道商品关系表数据
            this.cargowaySkuService.update(cargowaySku);
            // 更新货道表冗余信息
            this.cargowayService.updateCargoway(request.getCargowayId(), request.getCargowayVol());
            if (ObjectUtils.isEmpty(request.getInventory()) || request.getInventory()<0){
                throw new BizException(ErrorEnum.INVENTORY_ERROR, ErrorEnum.INVENTORY_ERROR.getMessage());
            }
            // 记录库存调整日志
            ReplenishmentRecordDO replenishmentRecordDO = this.replenishmentRecordDTOConverter.req2ReplenishmentRecord(request, sku.getSkuCode(), sku.getSkuName());
            this.replenishmentRecordService.add(replenishmentRecordDO);

        }
        return true;
    }

    public HardwareConfigDetailVO hardwareConfigDetail(Long deviceId) {
        // 查询设备
        DeviceDO currentDevice = this.service.findById(deviceId);

        // 查询主副设备
        DeviceDO deviceQueryParam = new DeviceDO();
        deviceQueryParam.setImei(currentDevice.getImei());
        List<DeviceDO> devices = this.service.findByModel(deviceQueryParam, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);

        // 查询相关货道
        Map<Long, List<CargowayDO>> cargowayMap = this.cargowayService.getCargowayMap(devices);
        List<HardwareConfigDetailVO.CabinetInfo> cabinetInfos = new ArrayList<>();
        devices.forEach(device -> {
            HardwareConfigDetailVO.CabinetInfo cabinetInfo = new HardwareConfigDetailVO.CabinetInfo();
            List<CargowayDO> cargowayList = cargowayMap.get(device.getId());
            cabinetInfo.setDeviceId(device.getId()).setDeviceType(device.getDeviceType()).setCargowayNum(cargowayList.size())
                    .setDeviceTypeName(DeviceTypeEnum.getName(device.getDeviceType()));

            if (!CollectionUtils.isEmpty(cargowayList)) {
                List<HardwareConfigDetailVO.CargowayDetail> cargowayDetails = new ArrayList<>();
                cargowayList.forEach(cargoway -> {
                    HardwareConfigDetailVO.CargowayDetail cargowayDetail = this.converter.data2HardwareConfigDetailVO(cargoway, currentDevice.getCtrlBoardNo());
                    cargowayDetails.add(cargowayDetail);
                });
                cabinetInfo.setCargowayList(cargowayDetails);
            }
            cabinetInfos.add(cabinetInfo);
        });

        return new HardwareConfigDetailVO(currentDevice.getDeviceName(), cabinetInfos);
    }

    public DeviceBaseInfoVO deviceBaseInfo(Long deviceId) {
        DeviceDO deviceDO = this.service.findById(deviceId);
        return this.converter.do2BaseInfoVo(deviceDO);
    }




    public Boolean updateVersion(DeviceVersionDTO req) {
        DeviceDO deviceDO = new DeviceDO();
        deviceDO.setImei(req.getImei());
        deviceDO.setCurrentVersion(req.getCurrentVersion());
        service.updateVersion(deviceDO);
        return true;
    }

    public AndroidDeviceVO getDeviceByImei(String imei) {
        DeviceDO deviceDO = this.service.getDeviceByImei(imei);

        if (deviceDO == null) {
            throw new BizException(ErrorEnum.DEVICE_NOT_FOUND, String.format(ErrorEnum.DEVICE_NOT_FOUND.getMessage(), imei));
        }

        return new AndroidDeviceVO(deviceDO.getId(), deviceDO.getDeviceName(), deviceDO.getFirmId(), deviceDO.getPin(), deviceDO.getDeviceType());
    }

    public EntDeviceDetailVO entDetail(Long deviceId) {
        DeviceDetailVO deviceDetailVO = this.detail(deviceId);
        return this.converter.detailVo2EntDetailVo(deviceDetailVO);
    }

    public PageInfoDTO<InventoryDeviceVO> findInventoryDevicePage(PageQueryDTO<InventoryReq> req) {
        List<InventoryDeviceVO> inventoryDeviceVOS =
                service.findInventoryDevicePage((req.getPageNo() -1)*req.getPageSize() , req.getPageSize(), req.getParam());
        if (CollectionUtils.isEmpty(inventoryDeviceVOS)) {
            return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), 0, null);
        }
        this.fillData(inventoryDeviceVOS);
        return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), service.getInventoryDeviceCount(req.getParam()), inventoryDeviceVOS);
    }

    public List<InventoryDeviceExcelVO> exportInventoryDevice(InventoryReq req) {
        List<InventoryDeviceVO> inventoryDeviceVOS =
                service.findInventoryDevicePage(CommonConstants.ZERO, CommonConstants.EXPORT_MAX_LIMIT, req);
        if (CollectionUtils.isEmpty(inventoryDeviceVOS)) {
            throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
        }
        this.fillData(inventoryDeviceVOS);
        return converter.deviceVO2ExcelVO(inventoryDeviceVOS);
    }

    public PageInfoDTO<InventorySkuVO> findInventorySkuPage(PageQueryDTO<InventoryReq> req) {
        List<InventorySkuVO> inventorySkuVOs =
                service.findInventorySkuPage((req.getPageNo() -1)*req.getPageSize(), req.getPageSize(), req.getParam());
        if (CollectionUtils.isEmpty(inventorySkuVOs)) {
            return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), 0, null);
        }
        this.fillData(inventorySkuVOs);
        return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), service.getInventorySkuCount(req.getParam()), inventorySkuVOs);
    }

    public List<InventorySkuExcelVO> exportInventorySku(InventoryReq req) {
        List<InventorySkuVO> inventorySkuVOs =
                service.findInventorySkuPage(CommonConstants.ZERO, CommonConstants.EXPORT_MAX_LIMIT, req);
        if (CollectionUtils.isEmpty(inventorySkuVOs)) {
            throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
        }
        this.fillData(inventorySkuVOs);
        return converter.skuVO2ExcelVO(inventorySkuVOs);
    }

    public PageInfoDTO<InventoryCargowayVO> findCargowayPage(PageQueryDTO<InventoryReq> req) {
        List<InventoryCargowayVO> inventoryCargowayVOS =
                service.findCargowayPage((req.getPageNo() -1)*req.getPageSize(), req.getPageSize(), req.getParam());
        if (CollectionUtils.isEmpty(inventoryCargowayVOS)) {
            return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), 0, null);
        }
        this.fillData(inventoryCargowayVOS);
        return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), service.getInventoryCargowayCount(req.getParam()), inventoryCargowayVOS);
    }

    public List<InventoryCargowayExcelVO> exportInventoryCargoway(InventoryReq req) {
        List<InventoryCargowayVO> inventoryCargowayVOS =
                service.findCargowayPage(CommonConstants.ZERO, CommonConstants.EXPORT_MAX_LIMIT, req);
        if (CollectionUtils.isEmpty(inventoryCargowayVOS)) {
            throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
        }
        this.fillData(inventoryCargowayVOS);
        return converter.cargowayVO2ExcelVO(inventoryCargowayVOS);
    }

    private <T extends InventorySkuVO> void fillData(List<T> inventorySkuVOs) {
        List<Long> firmIds = inventorySkuVOs.stream().map(InventorySkuVO::getFirmId).collect(Collectors.toList());
        Map<Long, String> firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);
        inventorySkuVOs.forEach(entity -> {
            // 公司名称
            entity.setFirmName(firmIdNameMap.get(entity.getFirmId()));
            CargowaySkuDO cargowaySkuDO = new CargowaySkuDO();
            cargowaySkuDO.setWeight(entity.getWeight());
            cargowaySkuDO.setSkuWeight(entity.getSkuWeight());
            cargowaySkuDO.setErrorRate(entity.getErrorRate());
            // 实时库存
            entity.setRealInventoryQty(BusinessUtil.calcQty(cargowaySkuDO));
        });
    }


    public boolean updateDevice(DeviceDTO dto) {

        // 获取设备柜子
        List<DeviceDO> devices = this.service.getDevicesByMasterDeviceId(dto.getId());
        String oldImei = devices.get(0).getImei();
        // imei有修改就校验imei  根据新imei 查询柜子
        if (StringUtils.hasText(dto.getImei()) && !oldImei.equals(dto.getImei())) {
            List<Long> deviceIds = devices.stream().map(DeviceDO::getId).collect(Collectors.toList());
            List<DeviceDO> existsDevices = this.service.getDevicesByImei(dto.getImei());
            existsDevices.forEach(f -> {
                if (!deviceIds.contains(f.getId())) {
                    throw new BizException(ErrorEnum.DATA_ALREADY_EXISTS, String.format(ErrorEnum.DATA_ALREADY_EXISTS.getMessage(), dto.getImei()));
                }
            });
            devices = devices.stream().filter(f -> !f.getId().equals(dto.getId())).collect(Collectors.toList());
            this.service.updateDevice(dto.getImei(), devices);
        }


        return this.service.update(this.converter.dto2Model(dto));
    }




    public List<AndroidDeviceAngleVO> queryAngleByImei(String imei) {
        List<DeviceDO> devices = this.service.getDevicesByImei(imei);
        List<CargowayDO> cargowayList = cargowayService.getCargowayList(devices.stream().map(DeviceDO::getId).collect(Collectors.toList()));
        List<AndroidDeviceAngleVO> list = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(cargowayList)) {
            cargowayList.forEach(cargowayDO -> {
                AndroidDeviceAngleVO androidDeviceAngleVO = new AndroidDeviceAngleVO();
                androidDeviceAngleVO.setAngle(cargowayDO.getAngle());
                androidDeviceAngleVO.setCargowayNo(cargowayDO.getCargowayNo());
                androidDeviceAngleVO.setLineNum(cargowayDO.getLineNum());
                list.add(androidDeviceAngleVO);
            });
        }
        return list;
    }
}

